package com.yvan.serverless.utils;

import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.yvan.Conv;
import com.yvan.YvanUtil;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.springframework.core.io.Resource;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

@Slf4j
public class FileUtilExt {

    public static final FileUtilExt Instance = new FileUtilExt();

    /**
     * 获取规则文件绝对路径
     */
    private static String getAbsolutePath(File file) {
        String filePath = file.getAbsolutePath();
        return filePath.replace("\\", "/")
                .replace("//", "/")
                .replace("/./", "/");
    }

    private static String normalizeSimple(String path) {
        if (Strings.isNullOrEmpty(path)) {
            return path;
        }

        if (path.toUpperCase().startsWith("FILE:")) {
            path = path.substring("file:".length());
        }

        return path;
    }

    /**
     * 规范路径
     * <pre>
     *     1. "\\" 所有斜杠都会被处理成反斜杠
     *     2. "./" 开头，将会被当前路径替代
     *     3. 路径符中的 "." 符将会被去掉
     *     4. 路径符中的 ".." 将会被处理成上级路径
     *     5. 去掉多余的 \\\\ 或 //
     * </pre>
     * <example>
     * [ "/app\\server/src", "../Reflect2.js" ] => "/app/server/Reflect2.js"
     * </example>
     */
    public static String normalizePath(Object... paths) {
        if (paths.length == 0) {
            return "";
        }
        List<String> fs = Lists.newArrayList();
        for (Object obj : paths) {
            if (obj instanceof String) {
                fs.add(normalizeSimple((String) obj));
            } else if (obj instanceof List) {
                for (Object v : (List) obj) {
                    fs.add(normalizeSimple(Conv.NS(v)));
                }
            } else if (obj instanceof String[]) {
                for (String v : (String[]) obj) {
                    fs.add(normalizeSimple(v));
                }
            } else if (obj instanceof Object[]) {
                for (Object v : (Object[]) obj) {
                    fs.add(normalizeSimple(Conv.NS(v)));
                }
            }
        }

        final String path = Joiner.on("/").join(fs);
        List<String> vs = Splitter.on('/').omitEmptyStrings().splitToList(path.replace("\\", "/"));
        String ret = Joiner.on("/").join(vs);
        // 翻译 "./" 处理成相对路径
        if (ret.startsWith(".")) {
            File file = new File(ret);
            ret = getAbsolutePath(file);
        }

        // 翻译 ".." 和 "." 上级运算符
        List<String> vss = new ArrayList<>(Splitter.on("/").splitToList(ret));
        boolean finded = true;
        while (finded) {
            finded = false;
            for (int i = 0; i < vss.size(); i++) {
                if (".".equals(vss.get(i))) {
                    vss.remove(i);  //删除"."
                    finded = true;
                    break;
                }
                if ("..".equals(vss.get(i))) {
                    vss.remove(i);  //删除".."
                    vss.remove(i - 1);  //删除".."的前一级路径
                    finded = true;
                    break;
                }
            }
        }

        return "/" + Joiner.on("/").join(YvanUtil.filter(vss, (v) -> !Strings.isNullOrEmpty(v)));
    }


    /**
     * 读取目标文件，并返回文件的所有内容
     */
    @SneakyThrows
    public static String readContent(File file) {
        if (!file.exists()) {
            return "";
        }
        try (InputStream is = new FileInputStream(file)) {
            List<String> lines = IOUtils.readLines(is, StandardCharsets.UTF_8);
            return Joiner.on("\n").join(lines);
        }
    }

    public static String readContent(Resource resource) throws IOException {
        try (InputStream is = resource.getInputStream()) {
            List<String> lines = IOUtils.readLines(is, StandardCharsets.UTF_8);
            return Joiner.on("\n").join(lines);
        }
    }
}
